package cn.gemiman.daoyi.module.cms.service.appsitecomment;

import cn.gemiman.daoyi.framework.common.enums.CommonStatusEnum;
import cn.gemiman.daoyi.framework.common.enums.UserTypeEnum;
import cn.gemiman.daoyi.framework.common.pojo.PageResult;
import cn.gemiman.daoyi.framework.common.util.object.BeanUtils;
import cn.gemiman.daoyi.framework.common.util.servlet.ServletUtils;
import cn.gemiman.daoyi.framework.ip.core.Area;
import cn.gemiman.daoyi.framework.ip.core.utils.IPUtils;
import cn.gemiman.daoyi.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.gemiman.daoyi.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
import cn.gemiman.daoyi.module.cms.controller.admin.appsitecomment.vo.AppSiteCommentPageReqVO;
import cn.gemiman.daoyi.module.cms.controller.admin.appsitecomment.vo.AppSiteCommentSaveReqVO;
import cn.gemiman.daoyi.module.cms.controller.admin.appsitecomment.vo.AppSiteCommentUpdateStatusReqVO;
import cn.gemiman.daoyi.module.cms.dal.dataobject.appsite.AppSiteDO;
import cn.gemiman.daoyi.module.cms.dal.dataobject.appsitecomment.AppSiteCommentDO;
import cn.gemiman.daoyi.module.cms.dal.dataobject.articledetail.ArticleDetailDO;
import cn.gemiman.daoyi.module.cms.dal.mysql.appsite.AppSiteMapper;
import cn.gemiman.daoyi.module.cms.dal.mysql.appsitecomment.AppSiteCommentMapper;
import cn.gemiman.daoyi.module.cms.dal.mysql.articledetail.ArticleDetailMapper;
import cn.gemiman.daoyi.module.cms.vo.WithLikeBaseVO;
import cn.gemiman.daoyi.module.member.api.user.MemberUserApi;
import cn.gemiman.daoyi.module.member.api.user.dto.MemberUserRespDTO;
import cn.gemiman.daoyi.module.system.api.user.AdminUserApi;
import cn.gemiman.daoyi.module.system.api.user.dto.AdminUserRespDTO;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.gemiman.daoyi.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.gemiman.daoyi.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.gemiman.daoyi.module.cms.enums.ErrorCodeConstants.*;

/**
 * 站点评论 Service 实现类
 *
 * @author 道一源码
 */
@Service
@Validated
public class AppSiteCommentServiceImpl implements AppSiteCommentService {

    @Resource
    private AppSiteCommentMapper appSiteCommentMapper;
    @Resource
    private MemberUserApi memberUserApi;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private AppSiteMapper appSiteMapper;
    @Resource
    private ArticleDetailMapper articleDetailMapper;

    @Override
    public Long createAppSiteComment(AppSiteCommentSaveReqVO createReqVO) {
        String clientIP = ServletUtils.getClientIP();
        createReqVO.setCreatorIp(clientIP);
        if (CharSequenceUtil.isNotBlank(clientIP)) {
            Area area = IPUtils.getArea(clientIP);
            if (null != area) {
                createReqVO.setCreatorCity(area.getName());
            }
        }
        // 插入
        AppSiteCommentDO appSiteComment = BeanUtils.toBean(createReqVO, AppSiteCommentDO.class);
        if (null != appSiteComment.getParentId() && appSiteComment.getParentId() > 0) {
            AppSiteCommentDO parent = this.validateAppSiteCommentExists(appSiteComment.getParentId());
            appSiteComment
                    .setAppId(parent.getAppId())
                    .setAppSiteId(parent.getAppSiteId())
                    .setCategoryId(parent.getCategoryId())
                    .setArticleId(parent.getArticleId())
                    .setTalkId(parent.getTalkId())
                    .setMessageId(parent.getMessageId());
            if (CollUtil.isEmpty(parent.getParentIds())) {
                parent.setParentIds(CollUtil.toList(parent.getParentId()));
                appSiteCommentMapper.updateById(parent);
            }
            List<Long> parentIds = parent.getParentIds();
            parentIds.add(appSiteComment.getParentId());
            appSiteComment.setParentIds(parentIds);
        } else {
            appSiteComment.setParentId(0L);
            appSiteComment.setParentIds(CollUtil.toList(appSiteComment.getParentId()));
        }
        if (null != appSiteComment.getArticleId()) {
            ArticleDetailDO articleDetailDO = articleDetailMapper.selectById(appSiteComment.getArticleId());
            appSiteComment.setCategoryId(articleDetailDO.getCategoryId());
        }
        if (null != appSiteComment.getUserId() && null != appSiteComment.getUserType()) {
            if (UserTypeEnum.MEMBER.getValue().equals(appSiteComment.getUserType())) {
                MemberUserRespDTO checkedData = memberUserApi.getUser(appSiteComment.getUserId()).getCheckedData();
                appSiteComment.setUserNickname(checkedData.getNickname());
                appSiteComment.setUserAvatar(checkedData.getAvatar());
            } else if (UserTypeEnum.ADMIN.getValue().equals(appSiteComment.getUserType())) {
                AdminUserRespDTO checkedData = adminUserApi.getUser(appSiteComment.getUserId()).getCheckedData();
                appSiteComment.setUserNickname(checkedData.getNickname());
                appSiteComment.setUserAvatar(checkedData.getAvatar());
            }
        }
        if (null == appSiteComment.getAppSiteId()) {
            AppSiteDO appSiteDO = appSiteMapper.selectOne(new LambdaQueryWrapperX<AppSiteDO>().eq(AppSiteDO::getAppId, createReqVO.getAppId()), false);
            appSiteComment.setAppSiteId(appSiteDO.getId());
        }
        appSiteCommentMapper.insert(appSiteComment
                .setStatus(CommonStatusEnum.DISABLE.getStatus())
                .setApproveStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()));
        // @TODO 暂时自动审批用于测试
        updateAppSiteCommentApproveStatus(new AppSiteCommentUpdateStatusReqVO().setId(appSiteComment.getId())
                .setApproveStatus(BpmProcessInstanceStatusEnum.APPROVE.getStatus())
        );
        // 返回
        return appSiteComment.getId();
    }

    @Override
    public void updateAppSiteComment(AppSiteCommentSaveReqVO updateReqVO, boolean checkSelf) {
        // 校验存在
        AppSiteCommentDO commentExists = validateAppSiteCommentExists(updateReqVO.getId());
        if (checkSelf && (!UserTypeEnum.MEMBER.getValue().equals(commentExists.getUserType()) || !ObjUtil.equals(commentExists.getUserId(), updateReqVO.getUserId()))) {
            throw exception(APP_SITE_COMMENT_NOT_SELF);
        }
        // 更新 内容
        appSiteCommentMapper.updateById(new AppSiteCommentDO().setId(updateReqVO.getId())
                .setCommentContent(updateReqVO.getCommentContent())
                .setSort(updateReqVO.getSort()).setApproveStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus())
                .setStatus(CommonStatusEnum.DISABLE.getStatus())
        );
    }

    @Override
    public void deleteAppSiteComment(Long id, boolean checkSelf) {
        // 校验存在
        AppSiteCommentDO commentExists = validateAppSiteCommentExists(id);
        if (checkSelf && (!UserTypeEnum.MEMBER.getValue().equals(commentExists.getUserType()) || !ObjUtil.equals(commentExists.getUserId(), getLoginUserId()))) {
            throw exception(APP_SITE_COMMENT_NOT_SELF);
        }
        // 删除
        appSiteCommentMapper.deleteById(id);
        List<Long> deleteIds;
        do {
            deleteIds = appSiteCommentMapper.selectNoParents();
            if (CollUtil.isNotEmpty(deleteIds)) {
                appSiteCommentMapper.deleteBatchIds(deleteIds);
            }
        } while (CollUtil.isNotEmpty(deleteIds));
    }

    private AppSiteCommentDO validateAppSiteCommentExists(Long id) {
        AppSiteCommentDO appSiteCommentDO = appSiteCommentMapper.selectById(id);
        if (appSiteCommentDO == null) {
            throw exception(APP_SITE_COMMENT_NOT_EXISTS);
        }
        return appSiteCommentDO;
    }

    @Override
    public AppSiteCommentDO getAppSiteComment(Long id) {
        return appSiteCommentMapper.selectById(id);
    }

    @Override
    public PageResult<AppSiteCommentDO> getAppSiteCommentPage(AppSiteCommentPageReqVO pageReqVO) {
        return appSiteCommentMapper.selectPage(pageReqVO);
    }

    @Override
    public void updateAppSiteCommentStatus(AppSiteCommentUpdateStatusReqVO updateReqVO) {
        // 校验存在
        validateAppSiteCommentExists(updateReqVO.getId());
        // 更新 状态
        appSiteCommentMapper.updateById(new AppSiteCommentDO().setId(updateReqVO.getId())
                .setStatus(updateReqVO.getStatus())
        );
    }

    @Override
    public void updateAppSiteCommentApproveStatus(AppSiteCommentUpdateStatusReqVO updateReqVO) {
        // 校验存在
        AppSiteCommentDO commentExists = validateAppSiteCommentExists(updateReqVO.getId());
        if (!BpmProcessInstanceStatusEnum.RUNNING.getStatus().equals(commentExists.getApproveStatus())) {
            throw exception(APP_SITE_COMMENT_NOT_RUNNING);
        }
        // 更新 状态
        appSiteCommentMapper.updateById(new AppSiteCommentDO().setId(updateReqVO.getId())
                .setApproveStatus(updateReqVO.getApproveStatus())
        );
        if (BpmProcessInstanceStatusEnum.APPROVE.getStatus().equals(updateReqVO.getApproveStatus()) && CommonStatusEnum.DISABLE.getStatus().equals(commentExists.getStatus())) {
            appSiteCommentMapper.updateById(new AppSiteCommentDO().setId(updateReqVO.getId())
                    .setStatus(CommonStatusEnum.ENABLE.getStatus())
            );
        }
    }

    @Override
    public List<AppSiteCommentDO> getAppSiteCommentListBatches(Collection<Long> ids) {
        return appSiteCommentMapper.selectBatchIds(ids);
    }

    @Override
    public <T extends WithLikeBaseVO<Long>> void generatorCommentTotal(List<T> list, SFunction<AppSiteCommentDO, Long> column) {
        if (CollUtil.isNotEmpty(list)) {
            Map<Long, Long> collect = appSiteCommentMapper.selectList(new LambdaQueryWrapperX<AppSiteCommentDO>()
                    .in(column, list.stream().map(T::getId).toList())
            ).stream().collect(Collectors.groupingBy(column, Collectors.counting()));
            list.parallelStream().forEach(c -> c.setCommentTotal(ObjectUtil.defaultIfNull(collect.get(c.getId()), 0L)));
        }
    }
}
